// benchmark.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <time.h>

#define FILENAME "testfile.dat"

void create_test_file(const char *filename, long long file_size) {
    int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (fd == -1) {
        perror("open");
        exit(1);
    }
    if (ftruncate(fd, file_size) == -1) {
        perror("ftruncate");
        exit(1);
    }
    // 可以选择性地写入随机数据
    close(fd);
    printf("Created test file '%s' of size %lld bytes.\n", filename, file_size);
}

int main(int argc, char **argv) {
    if (argc < 4) {
        fprintf(stderr, "Usage: %s <file_size_mb> <mode> <stride_kb|block_kb>\n", argv[0]);
        fprintf(stderr, "Modes: seq, stride\n");
        return 1;
    }

    long long file_size = atoll(argv[1]) * 1024 * 1024;
    const char *mode = argv[2];
    long param = atol(argv[3]) * 1024;

    create_test_file(FILENAME, file_size);

    int fd = open(FILENAME, O_RDONLY);
    if (fd == -1) {
        perror("open");
        return 1;
    }

    char *map = mmap(NULL, file_size, PROT_READ, MAP_SHARED, fd, 0);
    if (map == MAP_FAILED) {
        perror("mmap");
        close(fd);
        return 1;
    }
    
    printf("Starting access pattern: '%s'\n", mode);
    volatile char sink; // 防止编译器优化掉内存访问

    if (strcmp(mode, "seq") == 0) {
        long block_size = param;
        for (long i = 0; i < file_size; i += block_size) {
            sink = map[i];
        }
    } else if (strcmp(mode, "stride") == 0) {
        long stride = param;
        for (long i = 0; i < file_size; i += stride) {
            sink = map[i]; // 每次只访问一个字节，触发缺页
        }
    } else {
        fprintf(stderr, "Unknown mode: %s\n", mode);
    }

    printf("Access pattern finished.\n");

    munmap(map, file_size);
    close(fd);
    remove(FILENAME);

    return 0;
}